﻿#include "videofilter.h"

VideoFilter::VideoFilter()
{
    isRun = false;
}

VideoFilter::~VideoFilter()
{
    quit();
    wait();
}

void VideoFilter::setRunState(bool start)
{
    this->isRun = start;

    if(start)
        this->start();
}

void VideoFilter::setVideoParm(int width, int height, const QString &path)
{
    this->videoWidth = width;
    this->videoHeight = height;
    this->filePath = path;
}

void VideoFilter::run()
{
    /****************** 文件操作 *****************/
    //打开输入yuv
    std::string temp = this->filePath.toStdString();
    const char *inFileName = temp.c_str();
    FILE *inFile = fopen(inFileName, "rb+");
    if (!inFile)
    {
        printf("Fail to open file\n");
        return;
    }

    //创建输出yuv
    const char *outFileName = "videofilter.yuv";
    FILE *outFile = fopen(outFileName, "wb");
    if (!outFile)
    {
        printf("Fail to create file for output\n");
        return;
    }

    /****************** 过滤器操作 *****************/
    //也可使用avfilter_graph_parse方式内部解析构建

    //创建过滤器管理Graph
    AVFilterGraph *filterGraph = avfilter_graph_alloc();
    if (!filterGraph)
    {
        printf("Fail to create filter graph!\n");
        return;
    }

    //AVFilterGraph的输入源
    char args[512] = {0};
    sprintf(args, "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", this->videoWidth, this->videoHeight, AV_PIX_FMT_YUV420P, 1, 25, 1, 1);

    const AVFilter *bufferSrc = avfilter_get_by_name("buffer");
    AVFilterContext *bufferSrcCtx = NULL;
    int ret = avfilter_graph_create_filter(&bufferSrcCtx, bufferSrc, "in", args, NULL, filterGraph);
    if (ret < 0)
    {
        printf("Fail to create filter bufferSrc\n");
        return;
    }

    //AVFilterGraph的输出源
    AVBufferSinkParams *bufferSinkParams;
    enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};
    bufferSinkParams = av_buffersink_params_alloc();
    bufferSinkParams->pixel_fmts = pix_fmts;

    AVFilterContext *bufferSinkCtx = NULL;
    const AVFilter *bufferSink = avfilter_get_by_name("buffersink");
    ret = avfilter_graph_create_filter(&bufferSinkCtx, bufferSink, "out", NULL, bufferSinkParams, filterGraph);
    if (ret < 0)
    {
        printf("Fail to create filter sink filter\n");
        return;
    }

    //分离过滤器split
    const AVFilter *splitFilter = avfilter_get_by_name("split");
    AVFilterContext *splitFilterCtx;
    ret = avfilter_graph_create_filter(&splitFilterCtx, splitFilter, "split", "outputs=2", NULL, filterGraph);
    if (ret < 0)
    {
        printf("Fail to create split filter\n");
        return;
    }

    //裁剪过滤器crop
    const AVFilter *cropFilter = avfilter_get_by_name("crop");
    AVFilterContext *cropFilterCtx;
    ret = avfilter_graph_create_filter(&cropFilterCtx, cropFilter, "crop", "out_w=iw/2:out_h=ih:x=0:y=0", NULL, filterGraph);
    if (ret < 0)
    {
        printf("Fail to create crop filter\n");
        return;
    }

    //翻转过滤器 vflip hflip
    const AVFilter *flipFilter = avfilter_get_by_name("hflip");
    AVFilterContext *flipFilterCtx;
    ret = avfilter_graph_create_filter(&flipFilterCtx, flipFilter, "hflip", NULL, NULL, filterGraph);
    if (ret < 0)
    {
        printf("Fail to create vflip filter\n");
        return;
    }

    //水印过滤器 drawtext
    std::string info = "fontfile=./simhei.ttf:fontsize=60:fontcolor=green:alpha=0.8:x=30:y=30:text=Hello这是叠加层";
    const AVFilter *markFilter = avfilter_get_by_name("drawtext");
    AVFilterContext *markFilterCtx;
    ret = avfilter_graph_create_filter(&markFilterCtx, markFilter, "mark", info.c_str(), NULL, filterGraph);
    if (ret < 0)
    {
        printf("Fail to create mark filter\n");
        return;
    }

    //叠加过滤器overlay
    const AVFilter *overlayFilter = avfilter_get_by_name("overlay");
    AVFilterContext *overlayFilterCtx;
    ret = avfilter_graph_create_filter(&overlayFilterCtx, overlayFilter, "overlay", "x=W/2:y=0", NULL, filterGraph);
    if (ret < 0)
    {
        printf("Fail to create overlay filter\n");
        return;
    }

    //重要！开始设置多个过滤器的连接

    //输入源 连接 分离输入
    ret = avfilter_link(bufferSrcCtx, 0, splitFilterCtx, 0);
    if (ret != 0)
    {
        printf("Fail to link src filter and split filter\n");
        return;
    }

    //分离输出0 连接 叠加输入0
    ret = avfilter_link(splitFilterCtx, 0, overlayFilterCtx, 0);
    if (ret != 0)
    {
        printf("Fail to link split filter and overlay filter main pad\n");
        return;
    }

    //分离输出1 连接 裁剪输入
    ret = avfilter_link(splitFilterCtx, 1, cropFilterCtx, 0);
    if (ret != 0)
    {
        printf("Fail to link split filter's second pad and crop filter\n");
        return;
    }

    //裁剪输出 连接 翻转输入
    ret = avfilter_link(cropFilterCtx, 0, flipFilterCtx, 0);
    if (ret != 0)
    {
        printf("Fail to link crop filter and vflip filter\n");
        return;
    }

    //翻转输出 连接 水印输入
    ret = avfilter_link(flipFilterCtx, 0, markFilterCtx, 0);
    if (ret != 0)
    {
        printf("Fail to link crop filter and vflip filter\n");
        return;
    }

    //水印输出 连接 叠加输入1
    ret = avfilter_link(markFilterCtx, 0, overlayFilterCtx, 1);
    if (ret != 0)
    {
        printf("Fail to link vflip filter and overlay filter's second pad\n");
        return;
    }

    //叠加输出 连接 输出源
    ret = avfilter_link(overlayFilterCtx, 0, bufferSinkCtx, 0);
    if (ret != 0)
    {
        printf("Fail to link overlay filter and sink filter\n");
        return;
    }

    //以上配置完成 生效配置
    ret = avfilter_graph_config(filterGraph, NULL);
    if (ret < 0)
    {
        printf("Fail in filter graph\n");
        return;
    }

    /****************** 视频帧操作 *****************/
    //构造AVFrame
    AVFrame *frameIn = av_frame_alloc();
    unsigned char *frameBufferIn = (unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, videoWidth, videoHeight, 1));
    av_image_fill_arrays(frameIn->data, frameIn->linesize, frameBufferIn, AV_PIX_FMT_YUV420P, videoWidth, videoHeight, 1);

    AVFrame *frameOut= av_frame_alloc();
    unsigned char *frameBufferOut = (unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, videoWidth, videoHeight, 1));
    av_image_fill_arrays(frameOut->data, frameOut->linesize, frameBufferOut, AV_PIX_FMT_YUV420P, videoWidth, videoHeight, 1);

    frameIn->width = videoWidth;
    frameIn->height = videoHeight;
    frameIn->format = AV_PIX_FMT_YUV420P;
    uint32_t frameCount = 0;
    uint32_t oneFrameBytes = videoWidth * videoHeight * 3 / 2;

    while (isRun)
    {
        //读取yuv数据
        if(oneFrameBytes != fread(frameBufferIn, 1, oneFrameBytes, inFile))
        {
            qDebug() << "Read Finish! Total Frame" << frameCount;
            break;
        }

        //分配YUV数据
        frameIn->data[0] = frameBufferIn;
        frameIn->data[1] = frameBufferIn + videoWidth * videoHeight;
        frameIn->data[2] = frameBufferIn + videoWidth * videoHeight * 5 / 4;

        //过滤器写入原始视频帧
        if (av_buffersrc_add_frame(bufferSrcCtx, frameIn) < 0)
        {
            printf("Error while add frame.\n");
            break;
        }

        //过滤器读取处理好的视频帧
        ret = av_buffersink_get_frame(bufferSinkCtx, frameOut);
        if (ret < 0)
            break;

        //将过滤后的Frame写入文件
        if (frameOut->format == AV_PIX_FMT_YUV420P)
        {
            for (int i = 0; i < frameOut->height; i++)
            {
                fwrite(frameOut->data[0] + frameOut->linesize[0] * i, 1, frameOut->width, outFile);
            }

            for (int i = 0; i < frameOut->height / 2; i++)
            {
                fwrite(frameOut->data[1] + frameOut->linesize[1] * i, 1, frameOut->width / 2, outFile);
            }

            for (int i = 0; i < frameOut->height / 2; i++)
            {
                fwrite(frameOut->data[2] + frameOut->linesize[2] * i, 1, frameOut->width / 2, outFile);
            }
        }

        ++frameCount;
        av_frame_unref(frameOut);
    }

    //释放资源
    fclose(inFile);
    fclose(outFile);

    av_frame_free(&frameIn);
    av_frame_free(&frameOut);
    avfilter_graph_free(&filterGraph);

    isRun = false;
}
